package com.moandroid.cocos2d.types;

public class CCRect {
	public CCPoint origin;
	public CCSize size;
	
	public void setAll(float x, float y, float w, float h){
		origin.x = x;
		origin.y = y;
		size.width = w;
		size.height = h;
	}
	
	private CCRect() {
	    this(0, 0, 0, 0);
	}
	
	private CCRect(final CCPoint origin, final CCSize size) {
	    this(origin.x, origin.y, size.width, size.height);
	}
	
	public static CCRect make(final CCPoint origin, final CCSize size) {
	    return new CCRect(origin.x, origin.y, size.width, size.height);
	}
	
	public static CCRect make(float x, float y, float w, float h) {
	    return new CCRect(x, y, w, h);
	}
	
	private CCRect(float x, float y, float w, float h) {
	    origin = CCPoint.ccp(x, y);
	    size = CCSize.make(w, h);
	}
	
	public boolean contains(float x, float y) {
	    return size.width > 0 && size.height > 0  // check for empty first
	            && x >= origin.x && x < (origin.x + size.width)
	            && y >= origin.y && y < (origin.y + size.height);
	}
	
	public String toString() {
	    return "((" + origin.x + ", " + origin.y + "),(" + size.width + ", " + size.height + "))";
	}
	
	
	public static boolean equalToRect(final CCRect r1, final CCRect r2) {
	    return CCPoint.equalToPoint(r1.origin, r2.origin) && CCSize.equalToSize(r1.size, r2.size);
	}
	
	/**
	 * Returns true if aPoint is inside aRect.
	 */
	public static boolean containsPoint(final CCRect aRect, final CCPoint aPoint) {
	    return ((aPoint.x >= minX(aRect))
	            && (aPoint.y >= minY(aRect))
	            && (aPoint.x < maxX(aRect))
	            && (aPoint.y < maxY(aRect)));
	}
	
	public static boolean containsRect(final CCRect aRect, final CCRect bRect) {
	    return (!isEmptyRect(bRect)
	            && (minX(aRect) <= minX(bRect))
	            && (minY(aRect) <= minY(bRect))
	            && (maxX(aRect) >= maxX(bRect))
	            && (maxY(aRect) >= maxY(bRect)));
	}
	
	/**
	 * Returns the greatest x-coordinate value still inside aRect.
	 */
	public static float maxX(final CCRect aRect) {
	    return aRect.origin.x + aRect.size.width;
	}
	
	/**
	 * Returns the greatest y-coordinate value still inside aRect.
	 */
	public static float maxY(final CCRect aRect) {
	    return aRect.origin.y + aRect.size.height;
	}
	
	/**
	 * Returns the x-coordinate of aRect's middle point.
	 */
	public static float midX(CCRect aRect) {
	    return aRect.origin.x + (float) (aRect.size.width / 2.0);
	}
	
	/**
	 * Returns the y-coordinate of aRect's middle point.
	 */
	public static float midY(final CCRect aRect) {
	    return aRect.origin.y + (float) (aRect.size.height / 2.0);
	}
	
	/**
	 * Returns the least x-coordinate value still inside aRect.
	 */
	public static float minX(final CCRect aRect) {
	    return aRect.origin.x;
	}
	
	/**
	 * Returns the least y-coordinate value still inside aRect.
	 */
	public static float minY(final CCRect aRect) {
	    return aRect.origin.y;
	}
	
	/**
	 * Returns aRect's width.
	 */
	public static float width(final CCRect aRect) {
	    return aRect.size.width;
	}
	
	/**
	 * Returns aRect's height.
	 */
	public static float height(final CCRect aRect) {
	    return aRect.size.height;
	}
	
	
	public static boolean isEmptyRect(CCRect aRect) {
	    return (!(aRect.size.width > 0 && aRect.size.height > 0));
	}
	
	
	public enum Edge {
	    MinXEdge,
	    MinYEdge,
	    MaxXEdge,
	    MaxYEdge,
	}
	
	private static CCRect sRect = new CCRect();
	private static CCRect rRect = new CCRect();
	
	public static void divideRect(final CCRect aRect, CCRect[] slice, CCRect[] remainder, float amount, CCRect.Edge edge) {
	
	    if (slice == null)
	        slice = new CCRect[]{sRect};
	
	    if (remainder == null)
	        remainder = new CCRect[]{rRect};
	
	    if (isEmptyRect(aRect)) {
	        slice[0] = CCRect.make(0, 0, 0, 0);
	        remainder[0] = CCRect.make(0, 0, 0, 0);
	        return;
	    }
	
	    switch (edge) {
	        case MinXEdge:
	            if (amount > aRect.size.width) {
	                slice[0] = aRect;
	                remainder[0] = CCRect.make(maxX(aRect),
	                        aRect.origin.y,
	                        0,
	                        aRect.size.height);
	            } else {
	                slice[0] = CCRect.make(aRect.origin.x,
	                        aRect.origin.y,
	                        amount,
	                        aRect.size.height);
	                remainder[0] = CCRect.make(maxX(slice[0]),
	                        aRect.origin.y,
	                        maxX(aRect) - maxX(slice[0]),
	                        aRect.size.height);
	            }
	            break;
	        case MinYEdge:
	            if (amount > aRect.size.height) {
	                slice[0] = aRect;
	                remainder[0] = CCRect.make(aRect.origin.x,
	                        maxY(aRect),
	                        aRect.size.width, 0);
	            } else {
	                slice[0] = CCRect.make(aRect.origin.x,
	                        aRect.origin.y,
	                        aRect.size.width,
	                        amount);
	                remainder[0] = CCRect.make(aRect.origin.x,
	                        maxY(slice[0]),
	                        aRect.size.width,
	                        maxY(aRect) - maxY(slice[0]));
	            }
	            break;
	        case MaxXEdge:
	            if (amount > aRect.size.width) {
	                slice[0] = aRect;
	                remainder[0] = CCRect.make(aRect.origin.x,
	                        aRect.origin.y,
	                        0,
	                        aRect.size.height);
	            } else {
	                slice[0] = CCRect.make(maxX(aRect) - amount,
	                        aRect.origin.y,
	                        amount,
	                        aRect.size.height);
	                remainder[0] = CCRect.make(aRect.origin.x,
	                        aRect.origin.y,
	                        minX(slice[0]) - aRect.origin.x,
	                        aRect.size.height);
	            }
	            break;
	        case MaxYEdge:
	            if (amount > aRect.size.height) {
	                slice[0] = aRect;
	                remainder[0] = CCRect.make(aRect.origin.x,
	                        aRect.origin.y,
	                        aRect.size.width,
	                        0);
	            } else {
	                slice[0] = CCRect.make(aRect.origin.x,
	                        maxY(aRect) - amount,
	                        aRect.size.width,
	                        amount);
	                remainder[0] = CCRect.make(aRect.origin.x,
	                        aRect.origin.y,
	                        aRect.size.width,
	                        minY(slice[0]) - aRect.origin.y);
	            }
	            break;
	        default:
	            break;
	    }
	}
	
	public static CCRect rectApplyAffineTransform(CCRect aRect, CCAffineTransform matrix)
	{
	  CCRect r = CCRect.make(0, 0, 0, 0);
	  CCPoint[] p = new CCPoint[4];
	
	  for (int i = 0; i < 4; i++) {
	      p[i] = CCPoint.make(aRect.origin.x, aRect.origin.y);
	  }
	
	  p[1].x += aRect.size.width;
	  p[2].y += aRect.size.height;
	  p[3].x += aRect.size.width;
	  p[3].y += aRect.size.height;
	
	  for (int i = 0; i < 4; i++) {
	    p[i] = CCPoint.applyAffineTransform(p[i], matrix);
	  }
	
	  CCPoint min = CCPoint.make(p[0].x, p[0].y),
	          max = CCPoint.make(p[0].x, p[0].y);
	  for (int i = 1; i < 4; i++) {
	      min.x = Math.min(min.x, p[i].x);
	      min.y = Math.min(min.y, p[i].y);
	      max.x = Math.max(max.x, p[i].x);
	      max.y = Math.max(max.y, p[i].y);
	  }
	
	  r.origin.x = min.x; r.origin.y = min.y;
	  r.size.width = max.x - min.x;
	  r.size.height = max.y - min.y;
	
	  return r;
	}
}
